package logica;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

import frames.JFrameJuego;
import balas.Bala;
import naves.Daemonfeuer;
import naves.Haaslich;
import naves.Jugador;
import naves.Mordstier;
import naves.Siegbarste;
import naves.Enemiga;

public class SkyNet extends Thread {
	
	private boolean seDisparoBomba;
	private boolean llegoJefe;
	protected JFrameJuego juego;
	protected List<Bala> objetosEnemigos;
	protected List<Bala> objetosParaAgregar;
	protected List<Bala> objetosParaEliminar;
	protected Jugador amigo;
	private boolean escribirPuntaje;

	
	public SkyNet( JFrameJuego juego ) {
		this.juego = juego;
		this.objetosEnemigos = new CopyOnWriteArrayList<Bala>();
		this.objetosParaAgregar = new CopyOnWriteArrayList<Bala>();
		this.objetosParaEliminar = new CopyOnWriteArrayList<Bala>();
		this.seDisparoBomba=false;
		this.llegoJefe=false;
		this.escribirPuntaje=true;
	}

	/**
	 * agrega un elemento B a una lista de objetos a ser eliminados 
	 * @param b elemento para agregar en la lista
	 */
	public void eliminarObjeto(Bala b) {
		this.objetosParaEliminar.add(b);
		this.juego.eliminarObjeto(b);
	}

	/**
	 * agrega un objeto a una lista de objetos a ser visibles
	 * @param bec
	 */
	public void agregarObjeto(Bala bec) {
		this.objetosParaAgregar.add(bec);
		this.juego.agregarObjeto(bec);
		
	}
	
	public void run() {
		this.ordaDaemonfeuer();
		this.ordaHaaslich();
		this.ordaMordstier();
		juegoDeNaves();
		
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		this.llegoLaFinal();
		juegoDeNaves();

	}

	/**
	 * metodo parte del hilo que se encarga de chequear las colisiones posibles entre objetos
	 */
	private void juegoDeNaves(){
		while((!this.objetosEnemigos.isEmpty() && (this.amigo.getVida() > 0)) ) {
			if(seDisparoBomba==true){
				for(Bala e:objetosEnemigos){
					if(!e.getEsEnemigoFinal() && this.getJuego().contains(e.getLocation()))
						this.eliminarObjeto(e);
				}
				this.seDisparoBomba=false;
			}
			Iterator<Bala> i = this.objetosEnemigos.iterator();
			while(i.hasNext()) {
				Bala b = i.next();
				
				b.mover();
				if( this.juego.estaFueraDePantalla(b) ) {
					b.reLocation();
				} 
				else {
						if( b.getEsEnemigo() && this.amigo.alcanzoObjeto(b) ) {
							this.amigo.golpearObjeto(b);
						}
						else {
							if(!b.getEsEnemigo()){
								List<Bala> objEnemAux= objetosEnemigos;
								Iterator<Bala> j= objEnemAux.iterator();
								boolean alcanzo=false;
								while(j.hasNext() && !alcanzo){
									Bala aux=j.next();
									if(aux.getEsEnemigo() && b.alcanzoObjeto(aux)){
										b.golpearObjeto(aux);
										alcanzo=true;
									}
								}
							}
						}
				}		
			}			
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			eliminarEliminables();
			agregarAgregables();
			
			if(this.amigo.getCantVidas()<=0){
				for(Bala e:objetosEnemigos)
					juego.remove(e);
					
				juego.remove(amigo);
				setPuntajeFinal();
				this.juego.gameOver(false);
			}
			else
				if(this.llegoJefe==true && objetosEnemigos.size()==0){
					setPuntajeFinal();
					this.juego.gameOver(true);
				}
		}
	}
	
	/**
	 * metodo que crea un ejercito de naves Daemonfeuer
	 */
	private void ordaDaemonfeuer(){
		int maxWidth=this.getJuego().getJPanelNivel().getWidth();
		int maxHeight=this.getJuego().getJPanelNivel().getHeight();
		
		for( int i = 0; i < 10; i++ ) {
			Enemiga e = new Daemonfeuer(this);
			this.agregarObjeto(e);
			int posX = new Random(System.nanoTime()).nextInt(maxWidth);
			int posY = new Random(System.nanoTime()).nextInt(maxHeight);
			this.getJuego().getJPanelNivel().add(e);
			e.setLocation(posX, (-1*posY)-150);
		}
		this.agregarAgregables();
	}
	
	/**
	 * metodo que crea un ejercito de naves Haaslich
	 */
	private void ordaHaaslich(){		
		int maxWidth=this.getJuego().getJPanelNivel().getWidth();
		int maxHeight=this.getJuego().getJPanelNivel().getHeight();
		for( int i = 0; i <15; i++ ) {
			int x=(Math.random()<0.5)?0:1; 
			Enemiga e = new Haaslich(this,x);
			this.agregarObjeto(e);
			int posX = new Random(System.nanoTime()).nextInt(maxWidth);
			int posY = new Random(System.nanoTime()).nextInt(maxHeight);
			this.getJuego().getJPanelNivel().add(e);
			e.setLocation(posX, posY-1000);
		}
		this.agregarAgregables();
	}
		
	/**
	 * metodo que crea un ejercito de naves Mordstier
	 */
	private void ordaMordstier(){		
		Random rnd = new Random( System.nanoTime() );
		int maxHeight=this.getJuego().getJPanelNivel().getHeight();
		for( int i = 0; i < 5; i++ ) {
			Enemiga e = new Mordstier(this);
			this.agregarObjeto(e);
			int posY = new Random(System.nanoTime()).nextInt(maxHeight);
			this.getJuego().getJPanelNivel().add(e);			
			e.setLocation(rnd.nextInt(this.getJuego().getJPanelNivel().getWidth()), posY-500);
		}
		this.agregarAgregables();
	}

	/**
	 * metodo que crea un ejercito final, compuesto del jefe y 20 naves Haaslich enemigas
	 */
	private void llegoLaFinal(){
		this.llegoJefe=true;
		int maxWidth=this.getJuego().getJPanelNivel().getWidth();
		int maxHeight=this.getJuego().getJPanelNivel().getHeight();
		for(int i=0;i<1;i++){
			Enemiga e=new Siegbarste(this);
			this.agregarObjeto(e);
			int posX = new Random(System.nanoTime()).nextInt(maxWidth);
			int posY = new Random(System.nanoTime()).nextInt(maxHeight);
			this.getJuego().getJPanelNivel().add(e);
			e.setLocation(posX,posY-1000);
		}
		for( int i = 0; i <20; i++ ) {
			Enemiga e = new Haaslich(this,0);
			this.agregarObjeto(e);
			int posX = new Random(System.nanoTime()).nextInt(maxWidth);
			int posY = new Random(System.nanoTime()).nextInt(maxHeight);
			this.getJuego().getJPanelNivel().add(e);
			e.setLocation(posX, posY-1000);
		}
		this.agregarAgregables();
	}
	
	/**
	 * metodo que se encarga de controlar los enemigos que seguiran apareciendo en el juego
	 */
	public void agregarAgregables() {
		Iterator<Bala> i = this.objetosParaAgregar.iterator();
		while( i.hasNext() ) {
			Bala bala = i.next();
			this.objetosEnemigos.add(bala);
		}
		this.objetosParaAgregar = new CopyOnWriteArrayList<Bala>();
		
	}
	
	/**
	 * metodo que se encarga de eliminar los objetos que son balas o han colisionado
	 */
	public void eliminarEliminables() {
		Iterator<Bala> i = this.objetosParaEliminar.iterator();
		while( i.hasNext() ) {
			Bala bala = i.next();
			this.objetosEnemigos.remove(bala);
		}
		this.objetosParaEliminar = new CopyOnWriteArrayList<Bala>();
	}
	
	/**
	 * metodo que setea como verdadero que se va a usar la bomba atomica
	 */
	public void setSeDisparoBomba(){
		this.seDisparoBomba=true;
	}

	/**
	 * metodo que setea el puntaje final del jugador
	 */
	private void setPuntajeFinal(){
		try {
			if(this.escribirPuntaje==true){
			    PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("puntajes.txt", true)));
			    out.write(juego.getPuntaje()+"\n");
			    out.close();
			    this.escribirPuntaje=false;
			}
		} catch (IOException e) {
		    //exception handling left as an exercise for the reader
		}
	}
	
	/**
	 * @return the amigo
	 */
	public Jugador getAmigo() {
		return amigo;
	}

	/**
	 * @param amigo the amigo to set
	 */
	public void setAmigo(Jugador amigo) {
		this.amigo = amigo;
	}

	/**
	 * @return the juego
	 */
	public JFrameJuego getJuego() {
		return juego;
	}

}
